package com.effectivcrm.thymeleaf.extension;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.context.ApplicationContext;
import org.thymeleaf.Arguments;
import org.thymeleaf.Configuration;
import org.thymeleaf.dom.Element;
import org.thymeleaf.processor.attr.AbstractAttributeModifierAttrProcessor;
import org.thymeleaf.spring4.context.SpringWebContext;
import org.thymeleaf.standard.expression.IStandardExpression;
import org.thymeleaf.standard.expression.IStandardExpressionParser;
import org.thymeleaf.standard.expression.StandardExpressions;

import com.effectivcrm.domain.ui.Validation;

public class ValidatorAttributeProcessor extends
		AbstractAttributeModifierAttrProcessor {
	
	
	private List<ValidatorOutputStrategy> strategies;
	
	public ValidatorAttributeProcessor() {
		
		super("validations");
	}

	@Override
	protected ModificationType getModificationType(Arguments arguments,
			Element element, String attributeName, String newAttributeName) {
		// Just in case there already is a value set for the 'class' attribute
		// in the
		// tag, we will append our new value (using a whitespace separator)
		// instead
		// of simply substituting it.
		return ModificationType.APPEND_WITH_SPACE;
	}

	@Override
	protected Map<String, String> getModifiedAttributeValues(final Arguments arguments, final Element element, final String attributeName) {
		
		
		
		final Configuration configuration = arguments.getConfiguration();
		
		 /*
         * Obtain the attribute value
         */
        final String attributeValue = element.getAttributeValue(attributeName);

        /*
         * Obtain the Thymeleaf Standard Expression parser
         */
        final IStandardExpressionParser parser =
                StandardExpressions.getExpressionParser(configuration);

        /*
         * Parse the attribute value as a Thymeleaf Standard Expression
         */
        final IStandardExpression expression =
                parser.parseExpression(configuration, arguments, attributeValue);

        /*
         * Execute the expression just parsed
         */
        final Object val =
                 expression.execute(configuration, arguments);

        
        
        //get strategies to handle this.
        if(strategies == null) {
        	loadStrategies(arguments);
        }
        
        Map<String, String> modAttrValues = new HashMap<String, String>();
        
        if(val != null){
        	List<Validation> validations = (List<Validation>)val;
        	System.out.println("### validations ----> " + validations);
        	for(Validation v : validations) {
        		//apply output strategy
        		for(ValidatorOutputStrategy s : strategies) {
        			if(s.canHandle(v)){
        				s.handle(v, modAttrValues);
        			}
        		}
        	}
        }
        
        System.out.println("### modAttrValues ----> " + modAttrValues);
		return modAttrValues;
	}
	
	protected void loadStrategies(final Arguments arguments){
		/*
         * Obtain the Spring application context. Being a SpringMVC-based
         * application, we know that the IContext implementation being
         * used is SpringWebContext, and so we can directly cast and ask it
         * to return the AppCtx.
         */
        final ApplicationContext appCtx =
            ((SpringWebContext)arguments.getContext()).getApplicationContext();
        
        Map<String,ValidatorOutputStrategy> localStrategies = appCtx.getBeansOfType(ValidatorOutputStrategy.class);
       
        strategies = new ArrayList<ValidatorOutputStrategy>(localStrategies.values());
        
        System.out.println("### strategies ----> " + strategies);
	}
	
	@Override
	protected boolean recomputeProcessorsAfterExecution(
			final Arguments arguments, final Element element,
			final String attributeName) {
		// There is no need to recompute the element after this processor has
		// executed
		return false;
	}

	@Override
	protected boolean removeAttributeIfEmpty(final Arguments arguments,
			final Element element, final String attributeName,
			final String newAttributeName) {
		// If the resulting 'class' attribute is empty, do not show it at all.
		return true;
	}

	@Override
	public int getPrecedence() {

		return 12000;
	}

}
